package manager

import (
	"context"
	"github.com/tianjigames/fairy/constants"
	"github.com/tianjigames/fairy/model"
	protos2 "github.com/tianjigames/fairy/protos"
	"github.com/topfreegames/pitaya"
	"github.com/topfreegames/pitaya/logger"
	"sync"
)

var (
	TeamInfoManager *teamInfoManager
	teamInfoManagerOnce sync.Once
)

type teamInfoManager struct {
	BaseManager
	mapsTeams map[int]*protos2.MsgTeamInfo
}

func NewTeamInfoManager() *teamInfoManager {
	teamInfoManagerOnce.Do(func() {
		TeamInfoManager = &teamInfoManager{
			mapsTeams: map[int]*protos2.MsgTeamInfo{},
		}
	})
	return TeamInfoManager
}

/**
刷新组队列表 
 */
func (p *teamInfoManager) RefreshTeamMap(teamInfo *protos2.MsgTeamInfo)  {
	if teamInfo != nil {
		p.mapsTeams[int(teamInfo.GetTeamId())] = teamInfo
	}
}

/**
某个玩家要请某个玩家加入组队
 */
func (p *teamInfoManager) InviteJoinTeam(player *model.PlayerObject,toPlayerGuid int64,eType protos2.InviteType) error {
	info := player.TeamInfo 
	if info == nil { //首先创建一个组队
		err := p.CreateTeam(player)
		if err != nil {
			logger.Log.Errorf("[TeamInfoManager] CreateTeam failed,error:%s",err.Error())
			return err
		}
		player.PreInvitedPlayerGuid = toPlayerGuid
		return nil
	}

	if !player.IsTeamLeader() {
		PlayerManager.SendPacket(player,MessageError.GetCommonPromptPacket(constants.OperOnlyByTeamLeader,constants.MessageTypeNone))
		return nil
	}

	toPlayer := PlayerManager.GetOnLinePlayerByGuidId(toPlayerGuid)
	if toPlayer == nil {
		PlayerManager.SendPacket(player,MessageError.GetCommonPromptPacket(constants.RoleOffline,constants.MessageTypeNone))
	}

	if toPlayer.TeamInfo != nil {
		PlayerManager.SendPacket(player,MessageError.GetCommonPromptPacket(constants.PlayerInOtherTeam,constants.MessageTypeNone))
	}

	//给world发一条消息 添加到邀请列表
	err := pitaya.RPC(context.Background(),constants.GWInviteJoinTeamRoute,&protos2.GWInviteJoinTeamRet{},&protos2.GWInviteJoinTeam{
		PlayerId: int32(player.GetId()),
		ToPlayerId: int32(toPlayer.GetId()),
	})

	if err != nil {
		logger.Log.Errorf("[TeamInfoManager] InviteJoinTeam failed,error:%s",err.Error())
		return err
	}

	//给被邀请人发送一条消息
	builder := &protos2.GCRespInviteList{
		InviteInfo: []*protos2.MsgInviteInfo{
			{
				InviteId: info.TeamId,
				FromPlayerId: int32(player.GetId()),
				FromPlayerName: player.GetRoleName(),
				FromPlayerLevel: int32(player.GetLv()),
				FromPlayerCareerId: int32(player.GetCareerId()),
				MemberSize: int32(len(info.TeamMemberList)),
				MaxMemberSize: int32(constants.TeamMaxMember),
				InviteType: int32(eType),
			},
		},
	}

	err = PlayerManager.SendPacket(toPlayer,&model.MsgData{
		Route:constants.GCRespInviteList,
		Msg: builder,
	})

	if err != nil {
		logger.Log.Errorf("[TeamInfoManager] InviteJoinTeam failed,error:%s",err.Error())
		return err
	}

	return nil
}

/**
创建组队
 */
func (p *teamInfoManager) CreateTeam(player *model.PlayerObject) error {
	if player.TeamInfo != nil {
		logger.Log.Warnf("[TeamInfoManager] CreateTeam exist old team player:%d team:%d",player.GetId(),player.GetTeamId())
		PlayerManager.SendPacket(player,model.NewMsgData(constants.GCMyTeamRet,p.GetMyTeamPacket(player.TeamInfo)))
		return nil
	}

	at := constants.AttrMaxHp
	msg := &protos2.GWCreateTeam{
		PlayerId: int32(player.GetId()),
		PlayerName: player.GetRoleName(),
		Level: int32(player.GetLv()),
		Career: int32(player.GetCareerId()),
		SexId: int32(player.GetSexId()),
		MaxHp: int32(LoadPlayerInfoManager.GetAttrs(player,player.MAAttributeList,&at)),
	}

	err := pitaya.RPC(context.Background(),constants.GWCreateTeamRoute,&protos2.WGCreateTeamRet{},msg)
	if err != nil {
		logger.Log.Errorf("[TeamInfoManager] CreateTeam failed,error:%s",err.Error())
		return err
	}

	return nil
}


func (p *teamInfoManager) GetMyTeamPacket(teamInfo *protos2.MsgTeamInfo) *protos2.GCMyTeamRet {
	return &protos2.GCMyTeamRet{
		TeamInfo: teamInfo,
	}
}

/**
检查组队跟随
 */
func (p *teamInfoManager) CheckLeaderFollow(leader *model.PlayerObject) error {
	if leader.TeamInfo == nil {
		return nil
	}

	exists := make([]int,0)
	if len(leader.FollowIds) > 0 {
		change := false
		for _,memberId := range leader.FollowIds {
			exist := false
			for _,memberInfo := range leader.TeamInfo.TeamMemberList {
				if int(memberInfo.PlayerId) == memberId {
					exist = true
					break
				}
			}

			if exist {
				exists = append(exists,memberId)
			}else{
				change = true
			}
		}

		if change {
			leader.FollowIds = exists
			if len(exists) == 0 {//停止跟随
				err := p.StopFollow(leader,true)
				if err != nil {
					logger.Log.Errorf("[TeamInfoManager] CheckLeaderFollow failed,error:%s",err.Error())
					return err
				}
			}else{//通知跟随变更
				err := p.NotifyFollow(leader,true)
				if err != nil {
					logger.Log.Errorf("[TeamInfoManager] CheckLeaderFollow failed,error:%s",err.Error())
					return err
				}
			}
		}
	}

	return nil
}

/**
停止玩家跟随队长
 */
func (p *teamInfoManager) StopFollow(player *model.PlayerObject,isLeader bool) error {
	if isLeader {
		player.FollowIds = make([]int,0)
	}else{
		if !player.IsFollow() {
			return nil
		}

		at := constants.AttrMoveSpeed
		LoadPlayerInfoManager.ResetBaseAttr(player,&at)
	}

	player.FollowId = 0
	err := p.NotifyFollow(player,false)
	if err != nil {
		logger.Log.Errorf("[TeamInfoManager] StopFollow failed,error:%s",err.Error())
		return err
	}
	return nil
}

/**
通知玩家跟随
 */
func (p *teamInfoManager) NotifyFollow(player *model.PlayerObject,isFollow bool) error {
	var follow int32 = 0
	if isFollow {
		follow = 1
	}

	var followIds []int32
	if player.FollowIds != nil && len(player.FollowIds) > 0 {
		followIds = make([]int32,len(player.FollowIds))
		for _,id := range player.FollowIds {
			followIds = append(followIds,int32(id))
		}
	}

	err := PlayerManager.SendPacket(player,&model.MsgData{
		Route: constants.GCOperTeamFollow,
		Msg: &protos2.GCOperTeamFollow{
			Follow: follow,
			MemberId: followIds,
		},
	})

	if err != nil {
		logger.Log.Errorf("[TeamInfoManager] NotifyFollow failed,error:%s",err.Error())
		return err
	}

	return nil
}

/**
刷新玩家组队消息
 */
func (p *teamInfoManager) SendRefreshPlayerTeamInfo(player *model.PlayerObject) error {
	var isTeamLeader int32 = 0
	if player.IsTeamLeader() {
		isTeamLeader = 1
	}

	err := PlayerManager.BroadCastMessage(player.GetScene(),player,&model.MsgData{
		Route: constants.GCRefeshTeamInfo,
		Msg:&protos2.GCRefeshTeamInfo{
			PlayerId: int32(player.GetId()),
			TeamId: int32(player.GetTeamId()),
			IsLeader: isTeamLeader,
		},
	},false)
	if err != nil {
		logger.Log.Errorf("[TeamInfoManager] SendRefreshPlayerTeamInfo failed,error:%s",err.Error())
		return err
	}

	return nil
}

